using System;
using System.Diagnostics.Contracts;

namespace Charisma.Common.Disposable
{
  /// <summary>
  /// Disposes two <see cref="IDisposable"/> objects.
  /// </summary>
  [Serializable]
  public sealed class JoiningDisposable : IDisposable
  {
    private IDisposable first;
    private IDisposable second;

    /// <summary>
    /// Gets the first object to dispose.
    /// </summary>
    public IDisposable First
    {
      get { return first; }
    }

    /// <summary>
    /// Gets the second object to dispose.
    /// </summary>
    public IDisposable Second
    {
      get { return second; }
    }

    /// <summary>
    /// Joins the <see cref="JoiningDisposable"/> and <see cref="IDisposable"/>.
    /// </summary>
    /// <param name="first">The first disposable to join.</param>
    /// <param name="second">The second disposable to join.</param>
    /// <returns>New <see cref="JoiningDisposable"/> that will
    /// dispose both of them on its disposal</returns>
    public static JoiningDisposable operator &(JoiningDisposable first, IDisposable second)
    {
      Contract.Requires(first != null);
      Contract.Requires(second != null);

      if (second == null)
        return first;
      return new JoiningDisposable(first, second);
    }


    // Constructors

    
    public JoiningDisposable(IDisposable disposable1, IDisposable disposable2)
    {
      Contract.Requires(disposable1 != null);
      Contract.Requires(disposable2 != null);

      this.first = disposable1;
      this.second = disposable2;
    }

    /// <inheritdoc/>
    public void Dispose()
    {
      var disposable = first;
      first = null;
      try {
        disposable.DisposeSafely();
      }
      catch (Exception firstEx) {
        try
        {
          disposable = second;
          second = null;
          disposable.DisposeSafely();
          throw;
        }
        catch(Exception secondEx) {
          throw new AggregateException(firstEx, secondEx);
        }
      }
      disposable = second;
      second = null;
      disposable.DisposeSafely();
    }
  }
}